// *
// * Copyright (C) 2008 Roger Alsing : http://www.RogerAlsing.com
// *
// * This library is free software; you can redistribute it and/or modify it
// * under the terms of the GNU Lesser General Public License 2.1 or later, as
// * published by the Free Software Foundation. See the included license.txt
// * or http://www.gnu.org/copyleft/lesser.html for details.
// *
// *

using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using Alsing.Drawing;

namespace Alsing.Windows.Forms {
    [ToolboxItem(true)]
    public class BaseListBoxControl : ListBox {
        private const int WS_BORDER = unchecked(0x00800000);
        private const int WS_EX_CLIENTEDGE = unchecked(0x00000200);
        private Color borderColor = Color.Black;

        /// <summary> 
        /// Required designer variable.
        /// </summary>
        private BorderStyle borderStyle;

        private Container components;
        private bool RunOnce = true;


        public BaseListBoxControl() {
            SetStyle(ControlStyles.EnableNotifyMessage, true);
            BorderStyle = BorderStyle.FixedSingle;
        }

        [Browsable(false)]
        public Size WindowSize {
            get {
                var s = new APIRect();
                NativeMethods.GetWindowRect(Handle, ref s);
                return new Size(s.Width, s.Height);
            }
        }

        [Category("Appearance - Borders"), Description("The border color")]
        [DefaultValue(typeof (Color), "Black")]
        public Color BorderColor {
            get { return borderColor; }

            set {
                borderColor = value;
                Refresh();
                Invalidate();
                UpdateStyles();
            }
        }

        protected override CreateParams CreateParams {
            get {
                CreateParams cp = base.CreateParams;

                if (BorderStyle == BorderStyle.None) {
                    return cp;
                }

                cp.ExStyle &= (~WS_EX_CLIENTEDGE);
                cp.Style &= (~WS_BORDER);

                return cp;
            }
        }

        [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
        [Category("Appearance - Borders"), Description("The border style")]
        [DefaultValue(BorderStyle.None)]
        public new BorderStyle BorderStyle {
            get { return borderStyle; }
            set {
                if (borderStyle != value) {
                    if (!Enum.IsDefined(typeof (BorderStyle), value)) {
                        throw new InvalidEnumArgumentException("value", (int) value, typeof (BorderStyle));
                    }
                    borderStyle = value;
                    UpdateStyles();
                    Refresh();
                }
            }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), Obsolete("Do not use!", true)]
        public override Image BackgroundImage {
            get { return base.BackgroundImage; }
            set { base.BackgroundImage = value; }
        }


        [Browsable(false)]
        public int ClientWidth {
            get { return WindowSize.Width - (BorderWidth * 2); }
        }

        [Browsable(false)]
        public int ClientHeight {
            get { return WindowSize.Height - (BorderWidth * 2); }
        }

        [Browsable(false)]
        public int BorderWidth {
            get {
                switch (borderStyle) {
                    case BorderStyle.None: {
                        return 0;
                    }
                    case BorderStyle.Sunken: {
                        return 2;
                    }
                    case BorderStyle.SunkenThin: {
                        return 1;
                    }
                    case BorderStyle.Raised: {
                        return 2;
                    }

                    case BorderStyle.Etched: {
                        return 2;
                    }
                    case BorderStyle.Bump: {
                        return 6;
                    }
                    case BorderStyle.FixedSingle: {
                        return 1;
                    }
                    case BorderStyle.FixedDouble: {
                        return 2;
                    }
                    case BorderStyle.RaisedThin: {
                        return 1;
                    }
                    case BorderStyle.Dotted: {
                        return 1;
                    }
                    case BorderStyle.Dashed: {
                        return 1;
                    }
                }


                return Height;
            }
        }

        public event EventHandler Load = null;

        /// <summary> 
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose(bool disposing) {
            if (disposing) {
                if (components != null) {
                    components.Dispose();
                }
            }
            base.Dispose(disposing);
        }

        protected virtual void OnLoad(EventArgs e) {
            if (Load != null) {
                Load(this, e);
            }
            Refresh();
        }

        protected override unsafe void WndProc(ref Message m) {
            if (m.Msg == (int) WindowMessage.WM_NCPAINT) {
                try {
                    RenderBorder();
                } catch {}
                base.WndProc(ref m);
            } else if (m.Msg == (int) WindowMessage.WM_SHOWWINDOW) {
                if (RunOnce) {
                    RunOnce = false;
                    OnLoad(null);
                    base.WndProc(ref m);
                    UpdateStyles();
                } else {
                    UpdateStyles();
                    base.WndProc(ref m);
                }
            } else if (m.Msg == (int) WindowMessage.WM_NCCREATE) {
                base.WndProc(ref m);
            } else if (m.Msg == (int) WindowMessage.WM_NCCALCSIZE) {
                if (m.WParam == (IntPtr) 0) {
                    var pRC = (APIRect*) m.LParam;
                    //pRC->left -=3;
                    base.WndProc(ref m);
                } else if (m.WParam == (IntPtr) 1) {
                    var pNCP = (_NCCALCSIZE_PARAMS*) m.LParam;

                    base.WndProc(ref m);

                    int t = pNCP->NewRect.top + BorderWidth;
                    int l = pNCP->NewRect.left + BorderWidth;
                    int b = pNCP->NewRect.bottom - BorderWidth;
                    int r = pNCP->NewRect.right - BorderWidth;


                    pNCP->NewRect.top = t;
                    pNCP->NewRect.left = l;
                    pNCP->NewRect.right = r;
                    pNCP->NewRect.bottom = b;
                }
            } else {
                base.WndProc(ref m);
            }
        }

        private void RenderBorder() {
            IntPtr hdc = NativeMethods.GetWindowDC(Handle);
            var s = new APIRect();
            NativeMethods.GetWindowRect(Handle, ref s);

            using (Graphics g = Graphics.FromHdc(hdc)) {
                DrawingTools.DrawBorder((BorderStyle2) (int) BorderStyle, BorderColor, g,
                                        new Rectangle(0, 0, s.Width, s.Height));
            }
            NativeMethods.ReleaseDC(Handle, hdc);
        }


        protected override void OnEnter(EventArgs e) {
            base.OnEnter(e);
        }
    }
}